<?php

class ModelBase {

  protected static $table = null;
  protected static $pk = array("id");

  protected $connection = 'conexion';
  public  $data = array();
  protected $db = false;
  protected $logged = false;
  public $per_page = 30;  

  public function db($connection = NULL){
    // setea o devuelve la conexion a usar
    // la conexion debe ser un objeto de la clase DB
    // o una cadena que exista entre las "named connections" configuradas
    // por defecto se usa la conexion llamada "conexion"
    // especificada en la configuracion Config::get("conexion");

    if(is_null($connection)) {
      if(!$this->db) {
        $this->db = DB::getNamedInstance(Config::get($this->connection, 'local'));
      }
      return $this->db;
    }

    if(is_string($connection)){
      $this->db = DB::getNamedInstance($connection);
    } elseif(!get_class($connection) == "DB" && !is_subclass_of($connection, "DB")) {
      throw new Exception("Solo puede usar conexiones que sean instancias de la clase DB o subclases.");
    }

    $this->db = $connection;
    return $this;
  }

  public static function find($id_or_array){

    $id =& $id_or_array;
    
    if(is_array($id)){
      $params = array();
      $cond = array();
      foreach($id as $k => $v){
        $params[":".$k] = $v;
        $cond[] ="$k = :$k";
      }
    } else {
      $cond = array(static::$pk[0] . " = :" . static::$pk[0]);
      $params = array(":".static::$pk[0] => $id);
    }

    $cond = implode(" AND ", $cond);

    $classname = get_called_class();
    $recordset = new $classname();

    $result = $recordset->db()->executeOrException($q = "SELECT * FROM ".static::$table." WHERE ".$cond, $params);
    if($result->rowCount() == 1) {
      $recordset->data = $result->fetch(PDO::FETCH_ASSOC);
      return $recordset;
    }
    return $result;
  }

  public function data($data = null){

    if(is_null($data)) {
      return $this->data;
    } else {
      $this->data = $data;
      return $this;
    }

  }

  public function save(){
    if(empty($this->data)) return false;

    $keys = array_keys($this->data);
    try {
      $query =
      'INSERT INTO '.static::$table.' ('. implode(', ', $keys ) .') VALUES (:'. implode(', :', $keys ) .')';

      //Inspect::view($query);

      $data = $this->db()->executeOrException(
              $query,
              $this->data
              )->fetch(PDO::FETCH_ASSOC);
    } catch (Exception $e) {
      $query = 'UPDATE '.static::$table.' SET ';

      $fields = array();
      foreach($keys as $field){
        $fields[] = $field . " = :" . $field;
      }
      $query .= implode(", ", $fields) . " WHERE id = :id";

      //Inspect::view($query);

      $data = $this->db()->executeOrException(
              $query,
              $this->data
              )->fetch(PDO::FETCH_ASSOC);
    }

    if(!empty($data)) {
      $this->data = $data;
      $this->logged = true;
    }

    //Inspect::view($this->data);

    return $this;
  }

  public static function create($data = null){

    if(empty($data)) return false;

    $classname = get_called_class();

    $record = new $classname();

    $keys = array_keys($data);

    $query =
    'INSERT INTO '.static::$table.' ('. implode(', ', $keys ) .') VALUES (:'. implode(', :', $keys ) .')';

    //Inspect::view($query);

    $record->db()->executeOrException(
            $query,
            $data
            )->fetch(PDO::FETCH_ASSOC);

    

    //Inspect::view($new_user->data);

    return $classname::find($record->db()->lastInsertId());;
  }
  
  public function listPage($options = array()){
    
    $page   = isset($options["page"])? max(1, intval($options["page"])) : 1;
    $where  = isset($options["where"])? " WHERE " . $options["where"]: "";
    $order  = isset($options["order"])? " ORDER BY " . $options["order"] ." ": "";
    $params = isset($options["params"])? $options["params"]: array();
    $limit  = " LIMIT " . ($page-1) * $this->per_page .", ". $this->per_page ." ";
    
    return $this->db()->executeOrException(
      "SELECT * FROM ". static::$table . $where . $order . $limit ,
      $params
    )->fetchAll(PDO::FETCH_ASSOC);
  }
  
  public function lastPage($options = array()){
    $where  = isset($options["where"])? " WHERE " . $options["where"]: "";
    $params = isset($options["params"])? $options["params"]: array();
    
    $r = $this->db()->executeOrException(
      "SELECT count(*) as records FROM ". static::$table . $where,
      $params
    )->fetch(PDO::FETCH_ASSOC);
    
    return ceil($r['records']/$this->per_page);
  }
  
  public function delete($params = array()) {
    if(empty($params)){
        throw new Exception("No se puede borrar registros sin especificar condicion");
    }
    $where = array();
    $keys = array_keys($params);
    $prepared_params = array();
    foreach($keys as $key){
       $where[] = " $key = :$key";
       $prepared_params[":".$key] = $params[$key]; 
    }
    
    $r = $this->db()->executeOrException(
      "DELETE FROM ". static::$table . " WHERE ". implode(" AND ", $where),
      $prepared_params
    );
  }


}